import * as fsapi from 'fs-extra';
import { getOSType, OSType } from "../../common/utils/platform";
import { IServiceContainer } from "../../ioc/types";
import * as path from 'path';
import { ExecutionResult, IProcessServiceFactory, ShellOptions, SpawnOptions } from "../../common/process/types";
import { IDisposable } from '../../common/types';
import * as vscode from 'vscode';

let internalServiceContainer: IServiceContainer;
export function initializeExternalDependencies(serviceContainer: IServiceContainer): void {
    internalServiceContainer = serviceContainer;
}

export function normCasePath(filePath: string): string {
    return getOSType() === OSType.Windows ? path.normalize(filePath).toUpperCase() : path.normalize(filePath);
}

export async function shellExecute(command: string, options: ShellOptions = {}): Promise<ExecutionResult<string>> {
    const service = await internalServiceContainer.get<IProcessServiceFactory>(IProcessServiceFactory).create();
    return service.shellExec(command, options);
}

// filesystem
export function readFile(filePath: string): Promise<string> {
    return fsapi.readFile(filePath, 'utf-8');
}
export function pathExists(absPath: string): Promise<boolean> {
    return fsapi.pathExists(absPath);
}

export async function resolveSymbolicLink(absPath: string, stats?: fsapi.Stats): Promise<string> {
    stats = stats ?? (await fsapi.lstat(absPath));
    if (stats.isSymbolicLink()) {
        const link = await fsapi.readlink(absPath);
        // Result from readlink is not guaranteed to be an absolute path. For eg. on Mac it resolves
        //
        // The resultant path is reported relative to the symlink directory we resolve. Convert that to absolute path.
        const absLinkPath = path.isAbsolute(link) ? link : path.resolve(path.dirname(absPath), link);
        return resolveSymbolicLink(absLinkPath);
    }
    return absPath;
}
export function getWorkspaceFolders(): string[] {
    return vscode.workspace.workspaceFolders?.map((w) => w.uri.fsPath) ?? [];
}
export async function isFile(filePath: string): Promise<boolean> {
    const stats = await fsapi.lstat(filePath);
    if (stats.isSymbolicLink()) {
        const resolvedPath = await resolveSymbolicLink(filePath, stats);
        const resolvedStats = await fsapi.lstat(resolvedPath);
        return resolvedStats.isFile();
    }
    return stats.isFile();
}

export function onDidChangeEQSetting(name: string, callback: () => void): IDisposable {
    return vscode.workspace.onDidChangeConfiguration((event: vscode.ConfigurationChangeEvent) => {
        if (event.affectsConfiguration(`eq.${name}`)) {
            callback();
        }
    });
}
export function arePathsSame(path1: string, path2: string): boolean {
    return normCasePath(path1) === normCasePath(path2);
}
export function isParentPath(filePath: string, parentPath: string): boolean {
    if (!parentPath.endsWith(path.sep)) {
        parentPath += path.sep;
    }
    if (!filePath.endsWith(path.sep)) {
        filePath += path.sep;
    }
    return normCasePath(filePath).startsWith(normCasePath(parentPath));
}

export async function exec(file: string, args: string[], options: SpawnOptions = {}): Promise<ExecutionResult<string>> {
    const service = await internalServiceContainer.get<IProcessServiceFactory>(IProcessServiceFactory).create();
    return service.exec(file, args, options);
}